#pragma once

#include <memory>
#include <vector>
#include <Atom.h>
#include <xml/Stream.h>
#include <physics/DebugRenderer.h>
#include <physics/Types.h>

class b2World;

namespace liba
{ 
	namespace lib3d 
	{ 
		namespace hard 
		{
			class RenderList; 
			class Hardware;
		}
		namespace node { class Node; }
	}
}

namespace physics
{

class Node;
class Joint;

class World: private xml::ObjectANSI
{
private:
	friend class Node;
	friend class Joint;

	liba::lib3d::node::Node *sceneNode;

	std::auto_ptr <b2World> b2world;

	std::vector <Node*> nodes;
	std::vector <Joint*> joints;

	DebugRenderer * debugRenderer;
	
	int velocityIterations;
	int positionIterations;

	float pixelsInMeter;

public:
	World();
	virtual ~World();

private:
	virtual bool on_node(xml::Provider * prov, const std::string & name);
	virtual bool on_attribute(xml::Provider * prov, const std::string & name, const std::string & value);
	virtual bool on_end_node(xml::Provider *prov);

public:
	xml::ObjectANSI* GetLoader() { return this; }

	void SetRootNode(liba::lib3d::node::Node *node);

	static World* CreateFromResource(const liba::filesystem::String &fileName);

	void life_cycle(double deltaTime);
	
	Node * FindNode(const Atom & name);
	void AddNode(Node *node);
	void RemoveNode(Node *node, bool deleteNode = true);

	Joint * FindJoint(const Atom & name);
	template<class T>
	T * FindJoint(const Atom & name) { return dynamic_cast<T*>(FindJoint(name)); }
	void AddJoint(Joint *joint);
	void RemoveJoint(Joint *joint, bool deleteJoint = true);

	float GetPixelsInMeter() const { return pixelsInMeter; }
	
	void SetDebugRenderer(DebugRenderer *renderer);
	void RenderToList(lib3d::hard::Hardware *hardware, lib3d::hard::RenderList *renderList);
	
	Node* Pick(const Vector2 &pickPoint);
};

}